﻿using NetCore8Demo.Models.Communication.SerialPortFolder;
using NetCore8Demo.Tool;
using NetCore8Demo.ViewModels.Communication.SerialPortFolder;
using System.IO.Ports;

namespace NetCore8Demo.Views.Communication.SerialPortFolder
{
    public partial class TestSerialPortForm : Form
    {
        public TestSerialPortForm()
        {
            InitializeComponent();
        }


        #region 变量定义

        SerialPort _serialPort = new SerialPort();

        private string _selectPortName = "";
        private bool _isOpen;
        private string _logFilePath = "";
        private Thread? _cycleThread;

        private bool _isCycle;

        #endregion

        #region 初始化

        private void TestSerialPortForm_Load(object sender, EventArgs e)
        {
            InitControl();
            InitSerialPort();


        }

        private void InitSerialPort()
        {
            _serialPort.DataReceived += SerialPort_DataReceived;
        }

        private void InitControl()
        {
            PortNameComBoBox.Items.Clear();
            BaudRateComBoBox.Items.Clear();
            ParityComBoBox.Items.Clear();
            DataBitsComBoBox.Items.Clear();
            StopBitsComBoBox.Items.Clear();

            if (SerialPort.GetPortNames().Length > 0)
            {
                foreach (var item in SerialPort.GetPortNames())
                {
                    PortNameComBoBox.Items.Add(item);
                }

                foreach (var item in StaticSerialPort.BoundList)
                {
                    BaudRateComBoBox.Items.Add(item);
                }

                foreach (var item in Enum.GetValues(typeof(Parity)))
                {
                    ParityComBoBox.Items.Add(item);
                }

                foreach (var item in StaticSerialPort.DataBitList)
                {
                    DataBitsComBoBox.Items.Add(item);
                }

                foreach (var item in Enum.GetValues(typeof(StopBits)))
                {
                    StopBitsComBoBox.Items.Add(item);
                }

                ChangeComboboxEnable(true);
                OpenBtn.Enabled = true;
                PortNameComBoBox.SelectedIndex = 0;
                BaudRateComBoBox.SelectedIndex = 0;
                ParityComBoBox.SelectedIndex = 0;
                DataBitsComBoBox.SelectedIndex = 0;
                StopBitsComBoBox.SelectedIndex = 0;
            }
            else
            {
                OpenBtn.Enabled = false;
                PortNameComBoBox.Text = "";
                BaudRateComBoBox.Text = "";
                ParityComBoBox.Text = "";
                DataBitsComBoBox.Text = "";
                StopBitsComBoBox.Text = "";
                ChangeComboboxEnable(false);
            }



        }


        private void TestSerialPortForm_FormClosing(object sender, FormClosingEventArgs e)
        {

            try
            {
                Task.Run(() =>
                {
                    _isCycle = false;
                    if (_cycleThread is { IsAlive: true })
                    {
                        _cycleThread?.Join();
                    }

                    _serialPort.Close();
                });

            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }


        }

        #endregion

        #region 页面按钮

        private void OpenBtn_Click(object sender, EventArgs e)
        {
            try
            {
                if (_isOpen)
                {
                    _serialPort.Close();
                    OpenBtn.Text = "打开";
                    ChangeComboboxEnable(true);
                    ShowRecRichTextBox("连接关闭");
                }
                else
                {
                    _serialPort.PortName = PortNameComBoBox.Text;
                    _serialPort.BaudRate = BaudRateComBoBox.Text.ToInt32();
                    _serialPort.DataBits = DataBitsComBoBox.Text.ToInt32();

                    if (Enum.TryParse(StopBitsComBoBox.Text, out StopBits stopBit))
                    {

                        if (stopBit != StopBits.None)
                        {
                            _serialPort.StopBits = stopBit;
                        }
                    }

                    if (Enum.TryParse(ParityComBoBox.Text, out Parity parity))
                    {
                        _serialPort.Parity = parity;
                    }

                    _serialPort.Open();
                    ChangeComboboxEnable(false);
                    OpenBtn.Text = "关闭";
                    ShowRecRichTextBox("连接打开");
                }
                _selectPortName = PortNameComBoBox.Text;
                _isOpen = !_isOpen;
                ChangeRecRichLastEnd();
            }
            catch (Exception exception)
            {
                _isOpen = false;
                OpenBtn.Text = "打开";
                ShowRecRichTextBox(exception.Message);
            }
        }

        private void SendBtn_Click(object sender, EventArgs e)
        {
            try
            {
                var result = SendRichTextBox.Text;
                if (result.Length > 0)
                {
                    // true 表明已经处于循环发送状态，false 表明已经处于单次发送状态
                    if (_isCycle)
                    {
                        _isCycle = false;
                        SendBtn.Text = "发送";
                        _cycleThread?.Join();
                        DisableControls(true);
                    }
                    else
                    {
                        //循环发送
                        if (CycleCheckBox.Checked)
                        {
                            _cycleThread = new Thread(() =>
                            {
                                while (_isCycle)
                                {
                                    Thread.Sleep(CycleTimeTextBox.Text.ToInt32());
                                    SendMessage(result);
                                }
                            })
                            {
                                IsBackground = true
                            };
                            _isCycle = true;
                            _cycleThread?.Start();
                            DisableControls(false);
                            // 将发送选项设置为 disable
                            SendBtn.Text = "停止发送";
                        }
                        else
                        {
                            SendMessage(result);
                        }
                    }
                }
                else
                {
                    ShowRecRichTextBox("请输入发送内容!");
                }
            }
            catch (Exception exception)
            {
                ShowRecRichTextBox(exception.Message);
            }
        }

        private void ClearRecBtn_Click(object sender, EventArgs e)
        {
            RecRichTextBox.Text = "";
        }

        private void SaveLogCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (SaveLogCheckBox.Checked)
            {
                // 弹出保存文件对话框
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    _logFilePath = saveFileDialog.FileName;
                }

            }
        }

        #endregion

        #region 修改页面控件

        //接收页面信息
        public void ShowRecRichTextBox(string data)
        {
            UpdateUi(() =>
            {
                if (string.IsNullOrEmpty(data))
                {
                    RecRichTextBox.Text = "";
                }

                if (RecLogCheckBox.Checked)
                {
                    data = data.FormatStringLog();
                }
                else
                {
                    data += Environment.NewLine;
                }
                RecRichTextBox.AppendText(data);

                if (SaveLogCheckBox.Checked && !string.IsNullOrEmpty(_logFilePath))
                {
                    Log.WriteLogWithFileName(_logFilePath, data, false);
                }


                if (AutoCheckBox.Checked)
                {
                    RecRichTextBox.SelectionStart = RecRichTextBox.Text.Length;
                    RecRichTextBox.ScrollToCaret();
                }
            });
        }

        //切换串口设置状态
        private void ChangeComboboxEnable(bool enable)
        {
            PortNameComBoBox.Enabled = enable;
            BaudRateComBoBox.Enabled = enable;
            ParityComBoBox.Enabled = enable;
            DataBitsComBoBox.Enabled = enable;
            StopBitsComBoBox.Enabled = enable;
        }

        //发送数据 控件状态切换
        private void DisableControls(bool enable)
        {
            SendAsciiRadioBtn.Enabled = enable;
            SendHexRadioBtn.Enabled = enable;
            CycleCheckBox.Enabled = enable;
            CycleTimeTextBox.Enabled = enable;
            SendRichTextBox.Enabled = enable;
        }

        //光标移动到最下面
        private void ChangeRecRichLastEnd()
        {
            if (AutoCheckBox.Checked)
            {
                UpdateUi(() =>
                {
                    RecRichTextBox.SelectionStart = RecRichTextBox.Text.Length;
                    RecRichTextBox.ScrollToCaret();
                });
            }
        }





        private void UpdateUi(Action action)
        {

            try
            {
                if (this.IsHandleCreated) { this.Invoke(action); }
            }
            catch
            {
                // 关闭窗口时，页面线程如果还在更改控件，this.Invoke(action)会报控件已经被释放
            }
        }

        #endregion

        #region 主方法

        //接收数据
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            int len = _serialPort.BytesToRead;
            byte[] buffers = new byte[len];
            _serialPort.Read(buffers, 0, len);
            string data = System.Text.Encoding.UTF8.GetString(buffers);

            UpdateUi(() =>
            {
                ShowRecRichTextBox(RecAsciiRadioBtn.Checked
                    ? data
                    : string.Join(" ", buffers.Select(b => b.ToString("X2")).ToArray()));
                //ToString("X2") 将byte 转成两位的16进制字符，不足补0
            });
            ChangeRecRichLastEnd();

        }

        //发送数据
        private void SendMessage(string result)
        {


            if (!_isOpen)
            {
                ShowRecRichTextBox("串口未打开");
                return;
            }

            if (RandomCheckBox.Checked)
            {
                // 结果追加生成随机数
                result += new Random().Next(1, 999).ToString().PadLeft(3, '0');
            }

            if (SendAsciiRadioBtn.Checked)
            {
                if (ShowSendDataCheckBox.Checked)
                {
                    ShowRecRichTextBox(result);
                }
                
                if (_serialPort.IsOpen)
                {
                    _serialPort.Write(result);
                }
            }
            else
            {
                byte[] sendBytes = StrToToHexByte(result);

                if (sendBytes.Length > 0)
                {

                    ShowRecRichTextBox(string.Join(" ", sendBytes.Select(b => b.ToString("X2")).ToArray()));
                    if (_serialPort.IsOpen)
                    {
                        _serialPort.Write(sendBytes, 0, sendBytes.Length);
                    }

                }
            }

        }


        /// <summary>
        /// 字符串转16进制格式,不够自动前面补零
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private byte[] StrToToHexByte(string hexString)
        {
            int i;
            hexString = hexString.Replace(" ", "");//清除空格
            if ((hexString.Length % 2) != 0)//奇数个
            {
                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];

                try
                {
                    for (i = 0; i < (hexString.Length - 1) / 2; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);
                }
                catch
                {
                    ShowRecRichTextBox("含有非16进制字符");
                    return [];
                }

                return returnBytes;
            }
            else
            {
                byte[] returnBytes = new byte[(hexString.Length) / 2];
                try
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                }
                catch
                {
                    ShowRecRichTextBox("含有非16进制字符");
                    return [];
                }
                return returnBytes;
            }
        }

        #endregion

        #region 热插拔

        /// <summary>
        /// 串口使用中时，虚拟串口不能删掉
        /// 应该是用于比如Usb转串口的热拔插
        /// </summary>
        /// <param name="m"></param>

        protected override void WndProc(ref Message m)
        {
            //1.设备改变
            if (m.Msg == 0x0219)
            {
                //2.设备已拔出
                if (m.WParam.ToInt32() == 0x8004)
                {
                    //2.1 消息提醒
                    ShowRecRichTextBox("设备已拔出!");
                }
                // 3. 设备已连接
                else if (m.WParam.ToInt32() == 0x8000)
                {
                    ShowRecRichTextBox("设备已连接!");

                }


                InitControl();

                //2.2 重新获取串口
                string[] ports = SerialPort.GetPortNames();
                PortNameComBoBox.Text = "";
                PortNameComBoBox.Items.Clear();
                foreach (var item in ports)
                {
                    PortNameComBoBox.Items.Add(item);
                }

                if (!ports.Contains(_selectPortName))
                {
                    PortNameComBoBox.SelectedIndex = PortNameComBoBox.Items.Count > 0 ? 0 : -1;
                }
                else
                {
                    PortNameComBoBox.SelectedIndex = PortNameComBoBox.Items.IndexOf(_selectPortName);
                }



                //2 处理用户串口 (一般走不到这里，Usb转串口的可以热拔插)
                if (_isOpen)
                {
                    //串口变化后(拔掉后)找不到已经打开的串口了，就把打开的串口释放掉
                    if (!ports.Contains(_selectPortName))
                    {
                        //2.3.1 释放掉原先的串口资源
                        _serialPort?.Close();
                        _serialPort?.Dispose();
                        //2.3.2 断开连接，改变按钮文字
                        OpenBtn.Text = "打开";
                        ChangeComboboxEnable(true);
                        PortNameComBoBox.SelectedIndex = PortNameComBoBox.Items.Count > 0 ? 0 : -1;
                    }
                    else
                    {
                        //变化后的串口，还包含之前打开的串口，默认就选中之前打开的串口，如果还要支持重连，记录下当时的其它参数，再打开。
                        PortNameComBoBox.SelectedIndex = PortNameComBoBox.Items.IndexOf(_selectPortName);
                    }
                }

            }
            base.WndProc(ref m);
        }

#endregion
    }
}
